package com.bright.ghj.common.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Tz
 * @author hxj
 * @date 2024/01/22 15:03
 * @Description 时间工具类
 */
public class DateUtil {

    public static final Pattern REGEX_NORM = Pattern.compile("\\d{4}-\\d{1,2}-\\d{1,2}(\\s\\d{1,2}:\\d{1,2}(:\\d{1,2})?)?(.\\d{1,3})?");
    public static final DateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd");
    public static final DateFormat dhmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    public static final DateFormat dhmsFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 时区 - 默认
     */
    public static final String TIME_ZONE_DEFAULT = "GMT+8";

    /**
     * 秒转换成毫秒
     */
    public static final long SECOND_MILLIS = 1000;

    public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";

    /**
     * 将 LocalDateTime 转换成 Date
     *
     * @param date LocalDateTime
     * @return LocalDateTime
     */
    public static Date of(LocalDateTime date) {
        if (date == null) {
            return null;
        }
        // 将此日期时间与时区相结合以创建 ZonedDateTime
        ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
        // 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
        Instant instant = zonedDateTime.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return Date.from(instant);
    }

    /**
     * 将 Date 转换成 LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime of(Date date) {
        if (date == null) {
            return null;
        }
        // 转为时间戳
        Instant instant = date.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    public static Date addTime(Duration duration) {
        return new Date(System.currentTimeMillis() + duration.toMillis());
    }

    public static boolean isExpired(Date time) {
        return System.currentTimeMillis() > time.getTime();
    }

    public static boolean isExpired(LocalDateTime time) {
        LocalDateTime now = LocalDateTime.now();
        return now.isAfter(time);
    }

    public static long diff(Date endTime, Date startTime) {
        return endTime.getTime() - startTime.getTime();
    }

    /**
     * 获取这两个日期之间间隔多少天
     * @param endTime
     * @param startTime
     * @return
     */
    public static long getDaysBetween(Date endTime, Date startTime) {
        long diff = diff(endTime, startTime);
        return diff / (24 * 60 * 60 * 1000);
    }

    /**
     * 创建指定时间
     *
     * @param year  年
     * @param mouth 月
     * @param day   日
     * @return 指定时间
     */
    public static Date buildTime(int year, int mouth, int day) {
        return buildTime(year, mouth, day, 0, 0, 0);
    }

    /**
     * 创建指定时间
     *
     * @param year   年
     * @param mouth  月
     * @param day    日
     * @param hour   小时
     * @param minute 分钟
     * @param second 秒
     * @return 指定时间
     */
    public static Date buildTime(int year, int mouth, int day,
                                 int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, mouth - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        // 一般情况下，都是 0 毫秒
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date max(Date a, Date b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return a.compareTo(b) > 0 ? a : b;
    }

    public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return a.isAfter(b) ? a : b;
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param field  日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(int field, int amount) {
        return addDate(null, field, amount);
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param date   设置时间
     * @param field  日历字段 例如说，{@link Calendar#DAY_OF_MONTH} 等
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(Date date, int field, int amount) {
        if (amount == 0) {
            return date;
        }
        Calendar c = Calendar.getInstance();
        if (date != null) {
            c.setTime(date);
        }
        c.add(field, amount);
        return c.getTime();
    }

    /**
     * 获取当前的时间 格式为: {@link DateUtil#FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND}
     *
     * @return 返回当前时间的字符串形式
     */
    public static String getCurrentDateStr() {
        TimeZone timeZone = TimeZone.getTimeZone(TIME_ZONE_DEFAULT);
        TimeZone.setDefault(timeZone);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
        String format = LocalDateTime.now().format(dateTimeFormatter);
        return format;
    }

    /**
     * 获取当前的时间
     * <p>
     * 格式为: {@link DateUtil#FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND}
     * <p>
     * 时区为: {@link DateUtil#TIME_ZONE_DEFAULT}
     *
     * @return 返回当前时间的字符串形式
     */
    public static Date getCurrDate() {
        TimeZone tz = TimeZone.getTimeZone(TIME_ZONE_DEFAULT);
        TimeZone.setDefault(tz);

        GregorianCalendar now = new GregorianCalendar();

        SimpleDateFormat format = new SimpleDateFormat(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
        String nowDate = format.format(now.getTime());


        Date newNowDate = null;

        try {
            newNowDate = format.parse(nowDate);
        } catch (ParseException e1) {
            return new Date();
        }
        return newNowDate;
    }


    /**
     * 获取时间的年份、月份、天数
     * @param date          时间
     * @param yearMonthDay  获取的类型 1、年份。 2、月份。 3、天数。 没有则报异常
     * @return              返回日期的年份、月份或天数
     */
    public static String getYearOrMonthOrDay(Date date, Integer yearMonthDay) {
        String rvalue = "";
        SimpleDateFormat format = null;
        switch (yearMonthDay) {
            case 1:
                format = new SimpleDateFormat("yyyy", Locale.CHINA);
                rvalue = format.format(date);
                break;
            case 2:
                format = new SimpleDateFormat("MM", Locale.CHINA);
                rvalue = format.format(date);
                break;
            case 3:
                format = new SimpleDateFormat("dd", Locale.CHINA);
                rvalue = format.format(date);
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + yearMonthDay);
        }
        return rvalue;
    }


    /**
     * 获取指定年份和月份的天数 具体使用 {@link YearMonth} 实现
     * @param years     年份
     * @param months    月份
     * @return          给定年月在当前月的总天数
     */
    public static Integer getDaysInMonth(Integer years, Integer months) {
        // 获取指定年份和月份的天数
        YearMonth yearMonth = YearMonth.of(years, months);
        int daysInMonth = yearMonth.lengthOfMonth();
        return daysInMonth;
    }


    /**
     * 格式化日期 默认使用yyyy-MM-dd HH:mm:ss
     * @param date
     * @return
     */
    public static String formatDate(Object date) {
        return formatDate(date, dhmsFormat);
    }

    public static String formatDate(Object date, String pattern) {
        return formatDate(date, new SimpleDateFormat(pattern));
    }

    public static String formatDate(Object date, DateFormat dateFormat) {
        if (date == null) {
            date = new Date();
        }
        return dateFormat.format(date);
    }

    public static String getNowString() {
        return dhmsFormat.format(System.currentTimeMillis());
    }

    public static String getTodayString() {
        return dFormat.format(System.currentTimeMillis());
    }

    public static String getDateString(Date date) {
        if (date == null) return null;
        return dFormat.format(date);
    }

    public static Date parseStringFormat(String dtString, String format) throws ParseException {
        return new SimpleDateFormat(format).parse(dtString);
    }

    /**
     * 将日期字符串转Date 兼容各种格式 参照hutool的实现方法
     * @param dateStr
     * @return
     * @throws Exception
     */
    public static Date parseDateString(String dateStr) throws Exception {
        // 将年月日、斜杠等全部转换成横杠-格式
        String dateString = normalize(dateStr);
        Matcher matcher = REGEX_NORM.matcher(dateString);
        if (matcher.matches()) {
            // 数有多少个冒号 判断有没有时分秒
            int colonCount = StringUtil.countMatches(dateString, ':');
            switch (colonCount) {
                case 0:
                    return dFormat.parse(dateString);
                case 1:
                    return dhmFormat.parse(dateString);
                case 2:
                    return dhmsFormat.parse(dateString);
            }
        }
        throw new RuntimeException("日期格式转换失败！" + dateStr);
    }

//    public static boolean isValidExcelDate(double doubleValue) {
//        return org.apache.poi.ss.usermodel.DateUtil.isValidExcelDate(doubleValue);
//    }
//
//    public static Date getJavaDate(double doubleValue) {
//        return org.apache.poi.ss.usermodel.DateUtil.getJavaDate(doubleValue);
//    }

    private static String normalize(String dateStr) {
        if (StringUtil.isBlank(dateStr)) {
            return dateStr;
        } else {
            String[] dateAndTime = StringUtil.split(dateStr, ' ');
            int size = dateAndTime.length;
            if (size >= 1 && size <= 2) {
                StringBuilder builder = new StringBuilder();
                String datePart = (dateAndTime[0]).replaceAll("[/.年月]", "-");
                datePart = StringUtil.removeEnd(datePart, "日");
                builder.append(datePart);
                if (size == 2) {
                    builder.append(' ');
                    String timePart = (dateAndTime[1]).replaceAll("[时分秒]", ":");
                    timePart = StringUtil.removeEnd(timePart, ":");
                    timePart = timePart.replace(',', '.');
                    builder.append(timePart);
                }

                return builder.toString();
            } else {
                return dateStr;
            }
        }
    }

    /**
     * 返回中间有哪些年月的列表
     * @param start
     * @param end
     * @return
     */
    public static List<YearMonth> getYearMonthsBetween(LocalDate start, LocalDate end) {
        List<YearMonth> yearMonths = new ArrayList<>();
        YearMonth current = YearMonth.from(start);
        YearMonth endYearMonth = YearMonth.from(end);

        while (!current.isAfter(endYearMonth)) {
            yearMonths.add(current);
            current = current.plusMonths(1);
        }

        return yearMonths;
    }


    /**
     * @author dongBad
     */
    public static boolean isDataStr(String str){
        boolean rValue = false;
        SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
        try{
            format.setLenient(false);// 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.parse(str);
            rValue = true;

            if(rValue && StringUtil.indexOf(str, ".") != -1) {
                rValue = false;
            }

            if(rValue && StringUtil.left(str, str.indexOf("-")).length() != 4) {
                rValue = false;
            }
        }catch(Exception e){
            rValue = false;
        }
        return rValue;
    }

}
